/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse.gui.client;

import java.util.Vector;

import nfse.gui.client.reports.TopValues;
import nfse.gui.query.QueryInfo;
import nfse.gui.query.QueryResult;
import nfse.gui.query.TypeInfo;
import nfse.gui.record.FlexRecord;
import nfse.gui.record.FlexRecordField;
import nfse.gui.util.NetUtil;
import com.gwtext.client.widgets.MessageBox;
import com.gwtext.client.widgets.MessageBoxConfig;
import com.google.gwt.core.client.*;
import com.google.gwt.user.client.*;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.client.rpc.*;

public class AnalysisTab extends FlexTable implements PopupListener {
    NetFSEClient client = null;

    private boolean[] active = new boolean[0];

    // FlexTable browseTable = new FlexTable();

    private FlexTable[] dataTables = new FlexTable[0];

    // private DeleteDialogBox deleteDialog = null;

    private Hyperlink[] deleteLinks = new Hyperlink[0];

    private Hyperlink[] exportLinks = new Hyperlink[0];

    private Hyperlink[] firstLinks = new Hyperlink[0];

    private Hyperlink[] lastLinks = new Hyperlink[0];

    private int[] n = new int[0];

    private Hyperlink[] nextLinks = new Hyperlink[0];

    private int[] offsets = new int[0];

    private AnalysisOptionsDialog[] optionDialogs2 = new AnalysisOptionsDialog[0];

    private Hyperlink[] optionLinks = new Hyperlink[0];

    private String[] orderBy = new String[0];

    // private CheckBox[] myQueriesCheckBoxes = new CheckBox[0];

    private Hyperlink[] prevLinks = new Hyperlink[0];

    private String queryID = "";

    private int[] recordCounts = new int[0];

    private Hyperlink[] refreshSummaryLinks = new Hyperlink[0];

    private String[] schemas = new String[0];

    private Hyperlink[] showHideLinks = new Hyperlink[0];

    private Hyperlink[] showHideSummaryLinks = new Hyperlink[0];

    private Label[] statusLabels = new Label[0];

    private FlexTable[] summaryDataTables = new FlexTable[0];

    FlexTable summaryHeaderTable = new FlexTable();

    private Label[] summaryStatusLabels = new Label[0];

    FlexTable summaryTable = new FlexTable();

    FlexTable[] summaryTables = new FlexTable[0];

    FlexTable[][] summaryTablesByField = new FlexTable[0][0];

    private FlexTable[] tables = new FlexTable[0];

    private int[] typeIdxs = new int[0];

    private String[] typeNames = new String[0];

    private int[] types = new int[0];

    private String[] where = new String[0];

    public AnalysisTab(NetFSEClient client) {
        this.client = client;
        // deleteDialog = new DeleteDialogBox();
        // deleteDialog.addPopupListener(this);
    }

    public int[] getActiveTypes() {
        Vector<Integer> idxs = new Vector<Integer>();
        for (int i = 0; i < active.length; i++) {
            if (active[i]) {
                for (int x = 0; x < typeIdxs.length; x++) {
                    if (typeIdxs[x] == i) {
                        idxs.addElement(new Integer(types[i]));
                        break;
                    }
                }

            }
        }
        int[] temp = new int[idxs.size()];
        for (int i = 0; i < temp.length; i++) {
            temp[i] = idxs.elementAt(i);
            // System.out.println("Active: " + temp[i]);
        }
        return temp;
    }

    private void clearTable(int type) {
        FlexTable table = getDataTable(type);
        setTableActive(type, false);
        if (table != null)
            while (table.getRowCount() > 1)
                table.removeRow(1);
    }

    private void delete(String queryID, int type, String sql) {

        final int tempType = type;

        QueryServiceAsync NetFSEService = (QueryServiceAsync) GWT.create(QueryService.class);

        ServiceDefTarget endpoint = (ServiceDefTarget) NetFSEService;
        endpoint.setServiceEntryPoint(NetFSEClient.QUERY_URL);

        AsyncCallback callback = new AsyncCallback() {
            public void onFailure(Throwable caught) {
                NetFSEClient.redirectToHome();
            }

            public void onSuccess(Object result) {
                get(tempType, 0);
            }
        };

        NetFSEService.delete(queryID, type, sql, callback);

    }

    public int getRecordCount(int type) {
        return recordCounts[typeIdxs[type]];
    }

    public String getSchema(int type) {
        return schemas[typeIdxs[type]];
    }

    private void get(int type, int offset) {

        if (offset > getRecordCount(type))
            offset = 0;

        final int n = getN(type);
        final int tempType = type;
        final int tempTypeIdx = typeIdxs[type];
        final int tempOffset = offset;
        final int count = getRecordCount(type);
        QueryServiceAsync nfseService = (QueryServiceAsync) GWT.create(QueryService.class);

        ServiceDefTarget endpoint = (ServiceDefTarget) nfseService;
        endpoint.setServiceEntryPoint(NetFSEClient.QUERY_URL);

        AsyncCallback callback = new AsyncCallback() {

            public void onFailure(Throwable caught) {
                //NetFSEClient.redirectToHome();
            	Window.alert(caught.getMessage());
                // clearTable(tempType);
            }

            public void onSuccess(Object result) {
                statusLabels[tempTypeIdx].setText("Formatting data table; please wait");

                // if (getDataTable(tempType).getRowCount() > 1) {
                // return;
                // }

                QueryResult qr = (QueryResult) result;

                if (qr == null) {
                    String where = getWhere(tempType);
                    String orderBy = getOrderBy(tempType);
                    String str1 = "";
                    String str2 = "";
                    String title = "";
                    if (where.length() == 0 && orderBy.length() > 0) {
                        title = "Error in Order By Clause";
                        str1 = "Order By";
                        str2 = "<hr>Order By: <br><pre>" + orderBy + "</pre>";
                    } else if (where.length() > 0 && orderBy.length() == 0) {
                        title = "Error in Where Clause";
                        str1 = "Where";
                        str2 = "<hr>Where: <br><pre>" + where + "</pre>";
                    } else {
                        title = "Error in Where or Order By Clause";
                        str1 = "Where or Order By";
                        str2 = "<hr>Where: <br><pre>" + where + "</pre><hr>Order By: <br><pre>" + orderBy + "</pre>";
                    }
                    String html = "An error was returned by the server indicating an error in the " + str1
                            + " clause.<br>" + str2;
                    NetFSEClient.showGenericDialog(title, html);
                    statusLabels[tempTypeIdx]
                            .setText("Error retrieving records. Check Where and Order By SQL in Options.");
                    clearTable(tempType);
                    return;

                }

                // for (int i = 0; i < NetForSEUtil.TYPE_NAMES.length; i++) {
                setRecordCount(tempType, qr.count);
                // }

                setOffset(tempType, tempOffset);
                int first = tempOffset + 1;
                int last = tempOffset + n;
                if (last > qr.count)
                    last = qr.count;

                // Record[] records = qr.records;

                // for (int i = 0; i < records.length; i++)
                // System.out.println(records[i]);
                showTable(tempType);
                if (qr.count == -1) {
                    clearTable(tempType);
                    statusLabels[tempTypeIdx].setText("Data type not specified in original search.");
                    hideTable(tempType);
                    // System.out.println("Count is -1: " + tempType);
                } else {
                    updateTable(tempType, getTable(tempType), getDataTable(tempType), qr);
                    String status = "";
                    if (qr.flexRecordGroup.records.length > 0) {
                        status = "Displaying records " + first + "-" + last + " of " + getRecordCount(tempType);
                        schemas[typeIdxs[tempType]] = qr.schema;
                    } else
                        status = "No matching records found.";
                    if (qr.qs.status != 1)
                        status += " (Search in progress)";
                    statusLabels[tempTypeIdx].setText(status);
                }
            }
        };
        statusLabels[tempTypeIdx].setText("Retrieving records from database; please wait");

        nfseService.get(getQueryID(), n, offset, type, getWhere(type), getOrderBy(type), callback);
    }

    public boolean getActive(int type) {
        return active[typeIdxs[type]];
    }

    public String[] getActiveWhere() {
        int[] types = getActiveTypes();
        String[] temp = new String[types.length];
        for (int i = 0; i < types.length; i++)
            temp[i] = getWhere(types[i]);
        return temp;
    }

    private FlexTable getDataTable(int type) {
        return dataTables[typeIdxs[type]];
    }

    public int getN(int type) {
        return n[typeIdxs[type]];
    }

    public int getOffset(int type) {
        return offsets[typeIdxs[type]];
    }

    public String getOrderBy(int type) {
        return orderBy[typeIdxs[type]];
    }

    public String getQueryID() {
        return queryID;
    }

    private void getTypeSummary(String queryID, int type, int field, boolean updateHeader) {
        ReportServiceAsync nfseService = (ReportServiceAsync) GWT.create(ReportService.class);

        ServiceDefTarget endpoint = (ServiceDefTarget) nfseService;
        endpoint.setServiceEntryPoint(NetFSEClient.REPORT_URL);

        final String fieldName = client.getFieldName(field);
        final int tempField = field;
        final int tempType = type;
        final int typeIdx = typeIdxs[type];
        final String tempTypeName = typeNames[typeIdxs[type]];
        final FlexTable table = summaryTablesByField[typeIdxs[type]][field];
        final boolean tempUpdateHeader = updateHeader;

        AsyncCallback callback = new AsyncCallback() {
            public void onFailure(Throwable caught) {
                NetFSEClient.redirectToHome();
            }

            public void onSuccess(Object result) {
            	
                summaryStatusLabels[typeIdx].setText("Request complete.");

                while (table.getRowCount() > 0)
                    table.removeRow(0);

                // showSummary(tempType);

                TopValues temp = (TopValues) result;

                if (tempUpdateHeader) {
                    initSummaryTable(summaryTables[typeIdxs[tempType]], summaryDataTables[typeIdxs[tempType]], tempType);
                    if (temp.values.length > 0) {
                        summaryTables[typeIdxs[tempType]].setHTML(1, 0, "<b>" + temp.startTS + " to " + temp.endTS
                                + "</b>");
                    }
                }

                if (temp.values.length == 0) {
                    // //hideSummary(tempType);
                    return;
                } else {
                    //
                }
              
                table.setStyleName("nfsetable");
                table.addStyleName("nfsetbody");

                // table.getRowFormatter().setStyleName(0, "nfseth");

                FlexTable.FlexCellFormatter formatter = table.getFlexCellFormatter();

                table.setHTML(0, 0, "<h3>Top " + fieldName + "s</h3>");
                formatter.setColSpan(0, 0, 8);
                formatter.addStyleName(0, 0, "tdcenter");
                table.setHTML(1, 0, "<b>Value</b>");
                formatter.addStyleName(1, 0, "nfsetd");
                table.setHTML(1, 1, "<b>Start</b>");
                formatter.addStyleName(1, 1, "nfsetd");
                table.setHTML(1, 2, "<b></b>");
                formatter.addStyleName(1, 2, "nfsetd");
                table.setHTML(1, 3, "<b>End</b>");
                formatter.addStyleName(1, 3, "nfsetd");
                table.setHTML(1, 4, "<b>Low</b>");
                formatter.addStyleName(1, 4, "nfsetd");
                table.setHTML(1, 5, "<b>High</b>");
                formatter.addStyleName(1, 5, "nfsetd");
                table.setHTML(1, 6, "<b>Total</b>");
                formatter.addStyleName(1, 6, "nfsetd");
                table.setHTML(1, 7, "<b>% Activity</b>");
                formatter.addStyleName(1, 7, "nfsetd");
                table.getRowFormatter().addStyleName(1, "nfseth");
                
                for (int i = 0; i < temp.values.length; i++) {
                    String html = "<img src=\"/nfse/spark?height=20&type=line&color=blue&data=";

                    // if (i % 2 == 0)
                    // dstIpSummaryTable.getRowFormatter().setStyleName(i + 2,
                    // "nfsetr");
                    // else
                    table.getRowFormatter().setStyleName(i + 2, "nfsetrodd");

                    for (int j = 0; j < temp.stats[i].length; j++) {
                        if (j > 0)
                            html += ",";
                        html += temp.stats[i][j];
                    }
                    html += "\" />";
                    table.setHTML(i + 2, 0, temp.values[i]);
                    formatter.addStyleName(i + 2, 0, "nfsetd");
                    if (tempField == NetFSEClient.FIELD_DST_PORT)
                        formatter.addStyleName(i + 2, 0, "tdright");
                    table.setHTML(i + 2, 1, "" + temp.stats[i][0]);
                    formatter.addStyleName(i + 2, 1, "tdright");
                    formatter.addStyleName(i + 2, 1, "nfsetd");
                    table.setHTML(i + 2, 2, html);
                    formatter.addStyleName(i + 2, 2, "nfsetd");
                    table.setHTML(i + 2, 3, "" + temp.stats[i][temp.stats[i].length - 1]);
                    formatter.addStyleName(i + 2, 3, "nfsetd");
                    table.setHTML(i + 2, 4, "" + temp.lows[i]);
                    formatter.addStyleName(i + 2, 4, "nfsetd");
                    formatter.addStyleName(i + 2, 4, "tdright");
                    table.setHTML(i + 2, 5, "" + temp.highs[i]);
                    formatter.addStyleName(i + 2, 5, "tdright");
                    formatter.addStyleName(i + 2, 5, "nfsetd");
                    table.setHTML(i + 2, 6, "" + temp.totals[i]);
                    formatter.addStyleName(i + 2, 6, "tdright");
                    formatter.addStyleName(i + 2, 6, "nfsetd");
                    table.setHTML(i + 2, 7, "" + temp.percents[i] + "");
                    formatter.addStyleName(i + 2, 7, "tdright");
                    formatter.addStyleName(i + 2, 7, "nfsetd");
                }

            }
        };
        summaryStatusLabels[typeIdx].setText("Request in progress, please wait.");
        nfseService.getTopValues(queryID, type, field, 10, getWhere(type), callback);
    }

    public void setOffset(int type, int offset) {
        offsets[typeIdxs[type]] = offset;
    }

    public void setOrderBy(int type, String orderBy) {
        this.orderBy[typeIdxs[type]] = orderBy;
    }

    private String[] getWhere() {
        int[] types = client.getActiveTypes();
        String[] temp = new String[types.length];
        for (int i = 0; i < types.length; i++)
            temp[i] = getWhere(types[i]);
        return temp;
    }

    public String getWhere(int type) {
        return where[typeIdxs[type]];
    }

    private void hideSummary(int type) {
        FlexTable table = summaryDataTables[typeIdxs[type]];
        table.setVisible(false);
    }

    private void hideTable(int type) {
        FlexTable table = getTable(type);
        table.setVisible(false);
    }

    private void initResultTable(FlexTable table, FlexTable dataTable, int type, String[] colNames, String[] colFields) {
        // Build header
        FlexTable.FlexCellFormatter formatter = dataTable.getFlexCellFormatter();
        // dataTable.setBorderWidth(1);
        FlexTable nav = new FlexTable();
        final int typeIdx = typeIdxs[type];
        // HorizontalPanel nav = new HorizontalPanel();
        int idx = -1;
        nav.setWidget(0, ++idx, firstLinks[typeIdx]);
        nav.setHTML(0, ++idx, "|");
        nav.setWidget(0, ++idx, nextLinks[typeIdx]);
        nav.setHTML(0, ++idx, "|");
        nav.setWidget(0, ++idx, prevLinks[typeIdx]);
        nav.setHTML(0, ++idx, "|");
        nav.setWidget(0, ++idx, lastLinks[typeIdx]);
        nav.setHTML(0, ++idx, "|");
        nav.setWidget(0, ++idx, deleteLinks[typeIdx]);
        nav.setHTML(0, ++idx, "|");
        nav.setWidget(0, ++idx, exportLinks[typeIdx]);
        nav.setHTML(0, ++idx, "|");
        nav.setWidget(0, ++idx, optionLinks[typeIdx]);
        nav.setHTML(0, ++idx, "| <B>Status:</b>");
        nav.setWidget(0, ++idx, statusLabels[typeIdx]);

        FlexTable typeHeaderTable = new FlexTable();

        typeHeaderTable.setHTML(0, 0, "<h2>" + typeNames[typeIdx] + " Results<h2>");
        typeHeaderTable.setHTML(0, 1, "[");
        typeHeaderTable.getFlexCellFormatter().addStyleName(0, 1, "tdbottom");
        typeHeaderTable.setWidget(0, 2, showHideLinks[typeIdx]);
        typeHeaderTable.getFlexCellFormatter().addStyleName(0, 2, "tdbottom");
        typeHeaderTable.setHTML(0, 3, "]");
        typeHeaderTable.getFlexCellFormatter().addStyleName(0, 3, "tdbottom");
        table.setWidget(0, 0, typeHeaderTable);
        table.setWidget(1, 0, nav);

        final int tempType = type;
        final String[] fields = colFields;

        dataTable.setStyleName("nfsetable");
        dataTable.addStyleName("nfsetbody");

        for (int i = 0; i < colNames.length; i++) {
            if (colFields[i] != null) {
                final String field = colFields[i];

                Hyperlink sortLink = new Hyperlink(colNames[i], colNames[i] + i);
                final String[] orderByTemp = orderBy;
                sortLink.setHTML("<b>" + colNames[i] + "</b>");

                sortLink.addClickListener(new ClickListener() {
                    public void onClick(Widget sender) {

                        String ob = optionDialogs2[typeIdx].getOrderBy().trim();
                        if (ob.equals(field + " asc")) {
                            optionDialogs2[typeIdx].setOrderBy(field + " desc");
                        } else {
                            optionDialogs2[typeIdx].setOrderBy(field + " asc");
                        }
                        setOrderBy(tempType, optionDialogs2[typeIdx].getOrderBy());
                        get(tempType, 0);
                    }
                });
                dataTable.setWidget(0, i, sortLink);
            } else {
                dataTable.setHTML(0, i, "<b>" + colNames[i] + "</b>");
            }
            formatter.setWordWrap(0, i, false);
            formatter.addStyleName(0, i, "tdleft");
        }

        dataTable.getRowFormatter().setStyleName(0, "nfseth");

        table.setWidget(2, 0, dataTable);
    }

    private void initSummaryTable(FlexTable table, FlexTable dataTable, int type) {
        // Build header
        FlexTable.FlexCellFormatter formatter = dataTable.getFlexCellFormatter();
        FlexTable nav = new FlexTable();
        final int typeIdx = typeIdxs[type];

        int idx = -1;
        nav.setWidget(0, ++idx, refreshSummaryLinks[typeIdx]);
        nav.setHTML(0, ++idx, "| <B>Status:</b>");
        nav.setWidget(0, ++idx, summaryStatusLabels[typeIdx]);

        FlexTable typeHeaderTable = new FlexTable();

        typeHeaderTable.setHTML(0, 0, "<h2>" + typeNames[typeIdx] + " Summary<h2>");
        typeHeaderTable.setHTML(0, 1, "[");
        typeHeaderTable.getFlexCellFormatter().addStyleName(0, 1, "tdbottom");
        typeHeaderTable.setWidget(0, 2, showHideSummaryLinks[typeIdx]);
        typeHeaderTable.getFlexCellFormatter().addStyleName(0, 2, "tdbottom");
        typeHeaderTable.setHTML(0, 3, "]");
        typeHeaderTable.getFlexCellFormatter().addStyleName(0, 3, "tdbottom");
        table.setWidget(0, 0, typeHeaderTable);
        table.setWidget(2, 0, nav);

        // dataTable.setStyleName("nfsetable");
        // dataTable.addStyleName("nfsetbody");

        // dataTable.getRowFormatter().setStyleName(0, "nfseth");

        table.setWidget(3, 0, dataTable);
    }

    public void updateOptions(int type, String where, String orderBy, int n) {
        int typeIdx = this.typeIdxs[type];
        this.where[typeIdx] = where;

        this.orderBy[typeIdx] = orderBy;
        this.n[typeIdx] = n;
        this.get(type, 0);
    }

    public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
        try {
            BrowseOptionsDialogBox options = (BrowseOptionsDialogBox) sender;
            if (!options.isCancelled()) {
                int type = options.getType();
                int typeIdx = this.typeIdxs[type];
                where[typeIdx] = options.getWhere();

                orderBy[typeIdx] = options.getOrderBy();
                n[typeIdx] = options.getN();
                this.get(type, 0);
            }

        } catch (ClassCastException cce) {

        }

        try {
            DeleteDialogBox delete = (DeleteDialogBox) sender;
            if (!delete.isCancelled()) {
                String sql = delete.getDelete();
                delete(getQueryID(), delete.getType(), sql);
            }
        } catch (ClassCastException cce) {

        }

    }

    public void openQuery(String queryID) {
        this.queryID = queryID;
        final String tempQueryID = queryID;
        QueryServiceAsync nfseService = (QueryServiceAsync) GWT.create(QueryService.class);

        ServiceDefTarget endpoint = (ServiceDefTarget) nfseService;
        endpoint.setServiceEntryPoint(NetFSEClient.QUERY_URL);

        AsyncCallback callback = new AsyncCallback() {
            public void onFailure(Throwable caught) {
                NetFSEClient.redirectToHome();
            }

            public void onSuccess(Object result) {
                QueryInfo info = (QueryInfo) result;
                if (info == null) {
                    NetFSEClient.showGenericDialog("Invalid Search ID", "The Search ID specified ('" + tempQueryID
                            + "') was invalid.");
                } else {
                    setQuery(tempQueryID, info);
                }
            }
        };

        nfseService.getQueryInfo(queryID.trim(), callback);
    }

    public void setAnalysisOptions(int type, String where, String orderBy, int n) {
        int typeIdx = this.typeIdxs[type];
        this.where[typeIdx] = where;

        this.orderBy[typeIdx] = orderBy;
        this.n[typeIdx] = n;
        this.get(type, 0);
    }

    private void setQuery(String queryID, QueryInfo info) {
        this.queryID = queryID;
        for (int i = 0; i < this.recordCounts.length; i++)
            recordCounts[i] = -1;

        setupBrowseTable(this, info.types);

        this.setHTML(0, 0, "<h2> Search Results for " + queryID + "</h2>");
        this.setHTML(1, 0, info.note + "");
        if (info.note == null || info.note.length() == 0)
            this.setHTML(1, 0, "");
        // tabs.selectTab(2);

        for (int i = 0; i < types.length; i++) {
            while (tables[i].getRowCount() > 1)
                tables[i].removeRow(1);
            this.where[i] = "";
            this.orderBy[i] = "";
            this.optionDialogs2[i].reset();
            this.n[i] = 15;

            for (int j = 0; j < info.types.length; j++) {
                if (info.types[j] == types[i]) {
                    get(types[i], 0);
                    summary(types[i]);
                }
            }

        }

        // getQueryStats(queryID);
        // timeline();
        // summary();

    }

    public void setRecordCount(int type, int offset) {
        recordCounts[typeIdxs[type]] = offset;
    }

    private void setTableActive(int type, boolean act) {
        this.active[typeIdxs[type]] = act;
    }

    public void setTypes(TypeInfo typeInfo) {
        int numTypes = typeInfo.getNumTypes();
        int maxType = -1;

        this.n = new int[numTypes];
        this.refreshSummaryLinks = new Hyperlink[numTypes];
        this.firstLinks = new Hyperlink[numTypes];
        this.nextLinks = new Hyperlink[numTypes];
        this.prevLinks = new Hyperlink[numTypes];
        this.lastLinks = new Hyperlink[numTypes];
        this.deleteLinks = new Hyperlink[numTypes];
        this.exportLinks = new Hyperlink[numTypes];
        this.optionLinks = new Hyperlink[numTypes];
        // this.optionDialogs = new BrowseOptionsDialogBox[numTypes];
        this.optionDialogs2 = new AnalysisOptionsDialog[numTypes];
        this.statusLabels = new Label[numTypes];
        this.summaryStatusLabels = new Label[numTypes];
        this.recordCounts = new int[numTypes];
        this.schemas = new String[numTypes];
        this.where = new String[numTypes];
        this.active = new boolean[numTypes];
        this.orderBy = new String[numTypes];
        this.types = new int[numTypes];
        this.typeIdxs = new int[numTypes];
        this.typeNames = new String[numTypes];
        this.offsets = new int[numTypes];
        this.tables = new FlexTable[numTypes];
        this.showHideLinks = new Hyperlink[numTypes];
        this.showHideSummaryLinks = new Hyperlink[numTypes];
        this.dataTables = new FlexTable[numTypes];
        this.summaryDataTables = new FlexTable[numTypes];
        this.recordCounts = new int[numTypes];
        this.summaryTablesByField = new FlexTable[numTypes][15];
        this.summaryTables = new FlexTable[numTypes];

        int[] types = typeInfo.getTypes();
        for (int i = 0; i < numTypes; i++) {
            if (maxType < types[i])
                maxType = types[i];
        }

        this.typeIdxs = new int[maxType + 1];
        for (int i = 0; i < numTypes; i++) {
            final int type = types[i];
            final int typeIdx = i;

            refreshSummaryLinks[i] = new Hyperlink("Refresh", "Refresh" + type);
            // showHideLinks[i].setText("Hide");
            refreshSummaryLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    summary(type);
                }
            });

            tables[i] = new FlexTable();

            showHideLinks[i] = new Hyperlink("Hide", "Hide" + type);
            // showHideLinks[i].setText("Hide");
            showHideLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    String value = showHideLinks[typeIdx].getText();
                    if (value.equals("Show")) {
                        showHideLinks[typeIdx].setText("Hide");
                        dataTables[typeIdx].setVisible(true);
                    } else {
                        showHideLinks[typeIdx].setText("Show");
                        dataTables[typeIdx].setVisible(false);
                    }
                }
            });

            showHideSummaryLinks[i] = new Hyperlink("Hide", "Hide" + type);
            // showHideLinks[i].setText("Hide");
            showHideSummaryLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    String value = showHideSummaryLinks[typeIdx].getText();
                    if (value.equals("Show")) {
                        showHideSummaryLinks[typeIdx].setText("Hide");
                        summaryDataTables[typeIdx].setVisible(true);
                    } else {
                        showHideSummaryLinks[typeIdx].setText("Show");
                        summaryDataTables[typeIdx].setVisible(false);
                    }
                }
            });

            dataTables[i] = new FlexTable();
            summaryDataTables[i] = new FlexTable();
            typeIdxs[type] = i;

            recordCounts[i] = 0;

            this.types[i] = type;
            this.typeNames[i] = typeInfo.getTypeName(types[i]);
            this.schemas[i] = typeInfo.getSchema(types[i]);

            final String tempTypeName = this.typeNames[i];

            n[i] = 15;
            firstLinks[i] = new Hyperlink("First", "First" + i);
            firstLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    get(type, 0);
                }
            });
            nextLinks[i] = new Hyperlink("Next", "Next" + i);
            nextLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    int offset = getOffset(type) + getN(type);
                    get(type, offset);
                }
            });
            prevLinks[i] = new Hyperlink("Prev", "Prev" + i);
            prevLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    int offset = getOffset(type) - getN(type);
                    if (offset < 0)
                        offset = 0;
                    get(type, offset);
                }
            });
            lastLinks[i] = new Hyperlink("Last", "Last" + i);
            lastLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    int offset = (getRecordCount(type) / getN(type)) * getN(type);
                    get(type, offset);
                }
            });

            deleteLinks[i] = new Hyperlink("Delete", "Delete" + i);
            deleteLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    MessageBox.show(new MessageBoxConfig() {
                        {
                            setTitle("Delete for " + tempTypeName);
                            setMsg("Enter an SQL delete statement omitting the 'delete':");
                            setWidth(300);
                            setButtons(MessageBox.OKCANCEL);
                            setMultiline(true);
                            setCallback(new MessageBox.PromptCallback() {
                                public void execute(String btnID, String text) {
                                    if (btnID.equals("ok"))
                                        delete(getQueryID(), type, text);
                                }
                            });
                        }
                    });

                }
            });

            exportLinks[i] = new Hyperlink("Export", "Export" + i);
            exportLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    String url = "export?queryid=" + getQueryID() + "&type=" + type + "&where="
                            + NetUtil.convertToHex(getWhere(type)) + "&orderby=" + getOrderBy(type);
                    Window.open(url, "Export", "");
                }
            });

            // optionDialogs[i] = new BrowseOptionsDialogBox(type, tempTypeName,
            // getSchema(type));
            optionDialogs2[i] = new AnalysisOptionsDialog(this, type, tempTypeName, getSchema(type));
            // optionDialogs[i].addPopupListener(this);
            where[i] = "";
            orderBy[i] = "";
            recordCounts[i] = 0;

            optionLinks[i] = new Hyperlink("Options", "Options" + i);
            optionLinks[i].addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    // BrowseOptionsDialogBox popup = optionDialogs[typeIdx];
                    // popup.setPopupPosition(sender.getAbsoluteLeft(),
                    // sender.getAbsoluteTop());
                    // popup.show();
                    optionDialogs2[typeIdx].show();
                }
            });

            statusLabels[i] = new Label();
            statusLabels[i].setText("Idle");

            summaryStatusLabels[i] = new Label();
            summaryStatusLabels[i].setText("Idle");

            summaryTables[i] = new FlexTable();

            for (int j = 0; j < summaryTablesByField[i].length; j++) {
                summaryTablesByField[i][j] = new FlexTable();
                if (j == NetFSEClient.FIELD_SRC_IP) {
                    summaryDataTables[i].setWidget(0, 0, summaryTablesByField[i][j]);
                } else if (j == NetFSEClient.FIELD_DST_IP) {
                    summaryDataTables[i].setWidget(0, 1, summaryTablesByField[i][j]);
                } else if (j == NetFSEClient.FIELD_DST_PORT) {
                    summaryDataTables[i].setWidget(1, 0, summaryTablesByField[i][j]);
                } else if (j == NetFSEClient.FIELD_PROTOCOL) {
                    summaryDataTables[i].setWidget(1, 1, summaryTablesByField[i][j]);
                }
            }

        }

        setupBrowseTable(this, types);

    }

    private void setupBrowseTable(FlexTable table, int[] types) {
        while (table.getRowCount() > 0)
            table.removeRow(0);
        FlexTable.FlexCellFormatter formatter = table.getFlexCellFormatter();

        int idx = 0;

        table
                .setHTML(
                        ++idx,
                        0,
                        "To view Search Results, perform a search using the Search tab or click on a Search Result ID in the Search Results section of the Search Info tab.");
        for (int i = 0; i < types.length; i++) {
            table.setWidget(++idx, 0, tables[typeIdxs[types[i]]]);
            tables[typeIdxs[i]].setVisible(true);
            summaryTables[i].setWidget(2, 0, summaryDataTables[typeIdxs[types[i]]]);
            table.setWidget(++idx, 0, summaryTables[typeIdxs[types[i]]]);
            summaryTables[typeIdxs[i]].setVisible(true);
        }
    }

    private void showSummary(int type) {
        FlexTable table = summaryDataTables[typeIdxs[type]];
        if (!table.isVisible())
            table.setVisible(true);
    }

    private void showTable(int type) {
        FlexTable table = getTable(type);
        if (!table.isVisible())
            table.setVisible(true);
    }

    private void summary(int type) {
        summaryTables[typeIdxs[type]].setVisible(true);
        getTypeSummary(queryID, type, NetFSEClient.FIELD_DST_IP, true);
        getTypeSummary(queryID, type, NetFSEClient.FIELD_SRC_IP, false);
        getTypeSummary(queryID, type, NetFSEClient.FIELD_DST_PORT, false);
        getTypeSummary(queryID, type, NetFSEClient.FIELD_PROTOCOL, false);
    }

    private FlexTable getTable(int type) {
        return tables[typeIdxs[type]];
    }

    private void updateTable(int type, FlexTable table, FlexTable dataTable, QueryResult qr) {
        setTableActive(type, true);
        FlexTable.FlexCellFormatter formatter = dataTable.getFlexCellFormatter();

        if (table.getRowCount() <= 1) {
            // Build header
            String[] colNames = qr.flexRecordGroup.getFieldNames();
            String[] colFields = qr.flexRecordGroup.getColumnNames();
            initResultTable(table, dataTable, qr.flexRecordGroup.typeID, colNames, colFields);
            // System.out.println("Initialized result table.");
        }

        // while (dataTable.getRowCount() - 1 >
        // qr.flexRecordGroup.records.length)
        // dataTable.removeRow(dataTable.getRowCount() - 1);
        // while (dataTable.getRowCount() > 1)
        // dataTable.removeRow(dataTable.getRowCount() - 1);

        for (int i = 0; i < qr.flexRecordGroup.records.length; i++) {
            int idx = -1;
            dataTable.setHTML(i + 1, 0, "");
            if (i % 2 == 0) {
                dataTable.getRowFormatter().setStyleName(i + 1, "nfsetr");
            } else {
                dataTable.getRowFormatter().setStyleName(i + 1, "nfsetrodd");
            }

            FlexRecord rec = qr.flexRecordGroup.records[i];
            // System.out.println(rec);
            for (int x = 0; x < rec.values.length; x++) {
                idx++;
                formatter.addStyleName(i + 1, idx, "nfsetd");
                formatter.setWordWrap(i + 1, idx, false);
                switch (qr.flexRecordGroup.flexRecordFields[x].type) {
                case FlexRecordField.TYPE_FLOAT:
                    dataTable.setHTML(i + 1, idx, rec.values[x]);
                    formatter.addStyleName(i + 1, idx, "tdright");
                    break;
                case FlexRecordField.TYPE_INT:
                case FlexRecordField.TYPE_LONG:
                    switch (qr.flexRecordGroup.flexRecordFields[x].subType) {
                    case FlexRecordField.SUB_TYPE_BYTES:
                        if (rec.values[x].equals("-1"))
                            rec.values[x] = "-";
                        break;
                    case FlexRecordField.SUB_TYPE_PROTOCOL:
                        if (rec.values[x].equals("-1")) {
                            rec.values[x] = "-";
                        } else {
                            rec.values[x] = NetUtil.getProtocolName(Integer.parseInt(rec.values[x]));
                        }
                        break;
                    }
                    dataTable.setHTML(i + 1, idx, rec.values[x]);
                    formatter.addStyleName(i + 1, idx, "tdright");
                    break;
                case FlexRecordField.TYPE_BOOLEAN:
                    if (qr.flexRecordGroup.flexRecordFields[x].subType == FlexRecordField.SUB_TYPE_CHECK_MARK) {
                        if (rec.values[x].equals("Y"))
                            dataTable.setHTML(i + 1, idx, "<img src=\"image/checkmark.gif\"/>");
                        else
                            dataTable.setHTML(i + 1, idx, "");
                    } else {
                        dataTable.setHTML(i + 1, idx, rec.values[x]);
                    }
                    break;
                default:

                    if (qr.flexRecordGroup.flexRecordFields[x].subType == FlexRecordField.SUB_TYPE_IP_ADDR) {
                    	String tempURL = null;
                    	if ( rec.specialValues != null && rec.specialValues.length > x && rec.specialValues[x] != null) {
                            tempURL = rec.specialValues[x];
                    	}
                    	final String url = tempURL;
                    	if (url != null) {
                            Hyperlink ipLookup = new Hyperlink();
                            ipLookup.setHTML(rec.values[x]);
                            ipLookup.addClickListener(new ClickListener() {
                                public void onClick(Widget sender) {
                                    Window.open(url, "_nfse_iplookup", null);
                                    //IPLookupDialogBox ipDialog = new IPLookupDialogBox(ip);
                                    //ipDialog.show();
                                }
                            });
                            dataTable.setWidget(i + 1, idx, ipLookup);
                        } else {
                            dataTable.setHTML(i + 1, idx, rec.values[x]);
                        }
                    } else {
                        dataTable.setHTML(i + 1, idx, rec.values[x]);
                    }
                    break;
                }

            }

        }

        while (dataTable.getRowCount() > qr.flexRecordGroup.records.length + 1) {
            dataTable.removeRow(dataTable.getRowCount() - 1);
        }

        // dataTable.setVisible(false);
        // dataTable.setVisible(true);

    }
}
